#include <avr/io.h>
#include <avr/interrupt.h>

#include "avrlibtypes.h"
#include "avrlibdefs.h"
#include "common.h"
#include "a2d.h"

#define   BAT_MIN   512 // 3.3V / 2
#define   BAT_MAX   651 // 4.2V / 2

volatile u08 cflag;

//*****************************************************************************
CA2D::CA2D(void)
{
	cflag =FALSE;
	mode = 1;
}
//*****************************************************************************
void CA2D::init(void)
{
	sbi(ADCSR, ADEN);				// enable ADC (turn on ADC power)
	cbi(ADCSR, ADFR);				// default to single sample convert mode
	setprescaler(ADC_PRESCALE);	// set default prescaler
	setreference(ADC_REFERENCE);	// set default reference
	cbi(ADMUX, ADLAR);				// set to right-adjusted result
	sbi(ADCSR, ADIE);				// enable ADC interrupts
	cflag = FALSE;					// clear conversion complete flag
	sei();							// turn on interrupts (if not already on)
}
//*****************************************************************************
void CA2D::off(void)
{
	cbi(ADCSR, ADIE);				// disable ADC interrupts
	cbi(ADCSR, ADEN);				// disable ADC (turn off ADC power)
}
//*****************************************************************************
void CA2D::setprescaler(u08 prescale)
{
	outb(ADCSR, ((inb(ADCSR) & ~ADC_PRESCALE_MASK) | prescale));
}
//*****************************************************************************
void CA2D::setreference(u08 ref)
{
	outb(ADMUX, ((inb(ADMUX) & ~ADC_REFERENCE_MASK) | (ref<<6)));
}
//*****************************************************************************
void CA2D::setchannel(u08 ch)
{
	outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK));	// set channel
}
//*****************************************************************************
void CA2D::start(void)
{
	sbi(ADCSR, ADIF);	// clear hardware "conversion complete" flag 
	sbi(ADCSR, ADSC);	// start conversion
}
//*****************************************************************************
bool CA2D::finished(void)
{
	return bit_is_set(ADCSR, ADSC);
}

void CA2D::service(void){

	switch(mode){
		case 1:
		   batLevel=convert(0);
		   // it gives a value 1024 for +3V3
		   // a resistor bridge is put to down max +4V2 battery level around +2V07 on 100% battery charge
		   // minimum value for good battery +1V5, so with resistor bridge is set to +0V75
		   // values are from 204 to 567
		   if(batLevel<BAT_MIN) {
			   batLevel=0;
		   }
		   else {
			   batLevel=((batLevel-BAT_MIN)/(BAT_MAX-BAT_MIN))*100;
		   }
		   break;
	}
}


//*****************************************************************************
// Perform a 10-bit conversion
// starts conversion, waits until conversion is done, and returns result
u16 CA2D:: convert(u08 ch)
{
	cflag = FALSE;				// clear conversion complete flag
	outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK));	// set channel
	sbi(ADCSR, ADIF);						// clear hardware "conversion complete" flag 
	sbi(ADCSR, ADSC);						// start conversion
	//while(!cflag);				// wait until conversion complete
	//while( bit_is_clear(ADCSR, ADIF) );		// wait until conversion complete
	while( bit_is_set(ADCSR, ADSC) );		// wait until conversion complete

	// CAUTION: MUST READ ADCL BEFORE ADCH!!!
	return (inb(ADCL) | (inb(ADCH)<<8));	// read ADC (full 10 bits);
}

//*****************************************************************************
//! Interrupt handler for ADC complete interrupt.
SIGNAL(SIG_ADC)
{
	// set the a2d conversion flag to indicate "complete"
	cflag = TRUE;
}

